package cxy.spring_demo.display.iocContainerOverview.container;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * 通过接口内容来看，两者都是属于工厂模式用来创建对象使用的。
而区别在于
FactoryBean在BeanFacotry的实现中有着特殊的处理，如果一个对象实现了FactoryBean 那么通过它get出来的对象实际是
factoryBean.getObject() 得到的对象，如果想得到FactoryBean必须通过在 '&' + beanName 的方式获取

而ObjectFactory则只是一个普通的对象工厂接口。
在查看AbstractBeanFacotry的doGetBean(..) 部分的源码时，可以看到spring对ObjectFactory的应用之一就是，将创建对象
的步骤封装到ObjectFactory中 交给自定义的Scope来选择是否需要创建对象来灵活的实现scope。


通过这方面简单的对比可以得到：

    FactoryBean的着重于自定义创建对象过程，由BeanFactory通过FactoryBean来获取目标对象，而如果是isSingleton返回true的
    话spring会利用单例缓存来缓存通过FactoryBean创建的对象。

    而ObjectFactory就是一个普通的工厂对象接口，对于spring在doGetBean处的使用时，在于创建对象的过程由框架通过ObjectFactory定义，而
    创建的时机交给拓展接口Scope，除此之外ObjectFactory就是一个普通的接口。
    此外在将给依赖注入列表注册一个ObjectFactory类型的对象，在注入过程中会调用objectFactory.getObject()来创建目标对象注入进去。
    （如beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());）

    简单来说就是通过FactoryBean你可以控制对象如何创建，而ObjectFactory借助Scope接口自定义scope你可以控制对象的创建时机。
————————————————
版权声明：本文为CSDN博主「试水流连」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
原文链接：https://blog.csdn.net/m0_38043362/article/details/80284577
 * @author admin
 *
 */
@Configuration
public class ObjectFactoryVsFactoryBean {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
				ObjectFactoryVsFactoryBean.class);
		ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) applicationContext
				.getAutowireCapableBeanFactory();
		// 注册可被注入实例
		beanFactory.registerResolvableDependency(Person.class, new PersonObjectFactory());
		// 添加BeanDefinition
		RootBeanDefinition objectXDef = new RootBeanDefinition(ObjectX.class);
		objectXDef.setScope(BeanDefinition.SCOPE_PROTOTYPE);
		applicationContext.registerBeanDefinition("objectX", objectXDef);
		
		//false 因为BeanDefinition.SCOPE_PROTOTYPE
		System.out.println(applicationContext.getBean("objectX", ObjectX.class).person == applicationContext.getBean("objectX", ObjectX.class).person);

		// 输出com.example.lcc.basic.spring.factory.Application$Man@282003e1
		System.out.println(applicationContext.getBean("myFactoryBean"));
		// true 多次获取都是同一个man对象
		System.out.println(applicationContext.getBean("myFactoryBean") == applicationContext.getBean("myFactoryBean"));
		// 获取实际的工厂对象
		// 输出com.example.lcc.basic.spring.factory.Application$MyFactoryBean@7fad8c79
		System.out.println(applicationContext.getBean("&myFactoryBean"));
	}

	@Bean
	public FactoryBean<Man> myFactoryBean() {
		return new MyFactoryBean();
	}

	public static class MyFactoryBean implements FactoryBean<Man> {

		@Override
		public Man getObject() throws Exception {
			return new Man();
		}

		@Override
		public Class<?> getObjectType() {
			return Man.class;
		}

		@Override
		public boolean isSingleton() {
			return true;
		}
	}

	public static class ObjectX {
		@Autowired
		Person person;
	}

	public static class Person {

	}

	public static class Man {

	}

	public static class PersonObjectFactory implements ObjectFactory<Person> {

		@Override
		public Person getObject() throws BeansException {
			return new Person();
		}
	}

}
